package myJs

import myJs.Utils.{g, _}
import myJs.implicits.Implicits._
import myJs.myPkg.Implicits._
import myJs.myPkg._
import myJs.myPkg.jquery._
import org.scalajs.dom.{Element, Event, FormData, document}
import org.scalajs.dom.ext.Ajax
import org.scalajs.dom.raw.HTMLInputElement
import scalatags.Text.all._

import scala.collection.immutable.SeqMap
import scala.concurrent.ExecutionContext.Implicits.global
import scala.scalajs.js
import scala.scalajs.js.JSConverters._
import scala.scalajs.js.JSON
import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}
import myJs.myPkg.bootstrap.Bootstrap.default._

import scala.concurrent.Future

/**
 * Created by yz on 11/5/2020
 */
@JSExportTopLevel("DetailInfo")
object DetailInfo {

  val tableLsMap = SeqMap("junctionId" -> "JunctionID", "junctionLocation" -> "Junction location",
    "geneSymbol" -> "Gene symbol", "geneDescription" -> "Gene description", "geneType" -> "Gene type",
    "transcriptId" -> "Transcript ID", "tumorMedian" -> "Tumor median", "ntMedian" -> "NT median",
    "normalMedian" -> "Normal median", "tumorFreq" -> "Tumor frequency(sample number)",
    "ntFreq" -> "NT frequency(sample number)", "normalFreq" -> "Normal frequency(sample number)",
    "tumorSpecificTypes" -> "Tumor specific types",
    "alternativeSplicingTypes" -> "Alternative splicing types", "annotation" -> "Annotation",
    "tumorAssociatedGene" -> "Tumor associated gene"
  )
  val tableBsMap = SeqMap("junctionId" -> "JunctionID", "junctionLocation" -> "Junction location",
    "geneSymbol" -> "Gene symbol", "geneDescription" -> "Gene description", "geneType" -> "Gene type",
    "transcriptId" -> "Transcript ID", "tumorMedian" -> "Tumor median", "tumorFreq" -> "Tumor frequency(sample number)",
    "tumorAssociatedGene" -> "Tumor associated gene"
  )
  val tableFsMap = SeqMap("junctionId" -> "JunctionID", "junctionLocation" -> "Junction location",
    "geneSymbol1" -> "Gene symbol 1", "geneSymbol2" -> "Gene symbol 2", "geneDescription1" -> "Gene description 1",
    "geneDescription2" -> "Gene description 2", "geneType1" -> "Gene type 1",
    "geneType2" -> "Gene type 2",
    "tumorMedian" -> "Tumor median", "tumorFreq" -> "Tumor frequency(sample number)",
    "tumorAssociatedGene1" -> "Tumor associated gene 1", "tumorAssociatedGene2" -> "Tumor associated gene 2")
  val tableMap = Map("bs" -> tableBsMap, "ls" -> tableLsMap, "fs" -> tableFsMap)

  @JSExport("init")
  def init = {
    refreshKindTitle
    refreshTable(getJunctionId)
    refreshCancerNames
    refreshKind
    bootStrapValidator
    expressRun

    $("a[data-toggle='tab']").on("show.bs.tab", (y: Element, e: Event) => {
      val tabId = $(y).attr("href").get
      g.$("#logScale").bootstrapToggle()
      println(tabId)
    })

  }

  @JSExport("tcgaLogChange")
  def tcgaLogChange(y: Element) = {
    val checked = $(y).isChecked
    val logScale = if (checked) "TRUE" else "FALSE"
    Tool.useLoadingF() { () =>
      generateTcgaImage(logScale)
    }
  }

  @JSExport("gtexLogChange")
  def gtexLogChange(y: Element) = {
    val checked = $(y).isChecked
    val logScale = if (checked) "TRUE" else "FALSE"
    Tool.useLoadingF() { () =>
      generateGtexImage(logScale)
    }
  }

  def refreshKindTitle = {
    val kind = getKind
    val kindTitle = kind match {
      case "ls" => "Linear Splice"
      case "fs" => "Fusion"
      case "bs" => "Back-splice"
    }
    $("#kindTitle").text(kindTitle)
  }

  def refreshCancerNames = {
    val url = g.jsRoutes.controllers.SearchController.getAllKind().url.toString
    Ajax.get(url = s"${url}?junctionId=${getJunctionId}").map { xhr =>
      val data = JSON.parse(xhr.responseText).toJArS
      if (data.isEmpty) {
        $("#expressLi").hide()
      } else {
        val array = data.map { geneType =>
          js.Dictionary("text" -> geneType, "id" -> geneType)
        }
        val options = Select2Options.multiple(true).allowClear(true).placeholder("click to choose").dictData(array)
        Tool.getInputByName("kinds[]").select2(options)
      }
    }
  }

  def refreshKind = {
    val url = g.jsRoutes.controllers.SearchController.getAllKind().url.toString
    Ajax.get(url = s"${url}?junctionId=${getJunctionId}").map { xhr =>
      val data = JSON.parse(xhr.responseText).toJArS
      if (data.isEmpty) {
        $("#survivalLi").hide()
      } else {
        val array = data.map { geneType =>
          js.Dictionary("text" -> geneType, "id" -> geneType)
        }
        val options = Select2Options.dictData(array)
        Tool.getInputByName("kind").select2(options)
      }
    }
  }

  def refreshTable(junctionId: String) = {
    val kind = getKind
    val url = (kind match {
      case "fs" => g.jsRoutes.controllers.SearchController.getDetailFsById().url.toString
      case "ls" => g.jsRoutes.controllers.SearchController.getDetailLsById().url.toString
      case "bs" => g.jsRoutes.controllers.SearchController.getDetailBsById().url.toString
    })
    Ajax.get(url = s"${url}?junctionId=${junctionId}").map { xhr =>
      val data = xhr.responseText.toJDS
      val html = tableMap(kind).map { case (fieldName, header) =>
        val v = data(fieldName)
        val trueV = if (v.isDouble) {
          v.toDouble.toFixed(Tool.decDigits)
        } else v
        val finalV = if (fieldName == "geneDescription") {
          a(href := s"https://www.genenames.org/tools/search/#!/all?query=${data("geneSymbol")}", target := "_blank",
            trueV)
        } else span(trueV)
        tr(
          th(header),
          td(finalV)
        )
      }.mkString("&nbsp;")
      $("#table tbody").html(html)
    }
  }

  def getTcgaImage(logScale: String = "TRUE") = {
    val url = g.jsRoutes.controllers.SearchController.generateTcgaImage().url.toString
    val dict = js.Dictionary(
      "junctionId" -> getJunctionId,
      "logScale" -> logScale
    )
    Ajax.post(url = s"${url}", data = JSON.stringify(dict), headers = Map("Content-Type" -> "application/json"),
      responseType = "application/json").map { xhr =>
      xhr.responseText.toJDJAn
    }
  }

  def getGtexImage(logScale: String = "TRUE") = {
    val url = g.jsRoutes.controllers.SearchController.generateGtexImage().url.toString
    val dict = js.Dictionary(
      "junctionId" -> getJunctionId,
      "logScale" -> logScale
    )
    Ajax.post(url = s"${url}", data = JSON.stringify(dict), headers = Map("Content-Type" -> "application/json"),
      responseType = "application/json").map { xhr =>
      xhr.responseText.toJDJAn
    }
  }

  def checkInGtex = {
    val url = g.jsRoutes.controllers.SearchController.checkInGtex().url.toString
    Ajax.get(url = s"${url}?junctionId=${getJunctionId}").map { xhr =>
      xhr.responseText.toB
    }
  }

  def checkInTcga = {
    val url = g.jsRoutes.controllers.SearchController.checkInTcga().url.toString
    Ajax.get(url = s"${url}?junctionId=${getJunctionId}").map { xhr =>
      xhr.responseText.toB
    }
  }

  @JSExport("expressRun")
  def expressRun = {
    Tool.useLoadingF() { () =>
      val gtexF = checkInGtex.flatMap { b =>
        if (b) {
          generateGtexImage()
        } else {
          Future {
            $("#gtexResult").hide()
          }
        }
      }

      val tcgaF = checkInTcga.flatMap { b =>
        if (b) {
          generateTcgaImage()
        } else {
          Future {
            $("#tcgaResult").hide()
          }
        }
      }
      tcgaF.zip(gtexF).map { x =>
        val tcgaIsHidden = $("#tcgaResult").isHidden
        val gtexIsHidden = $("#gtexResult").isHidden
        if (tcgaIsHidden && gtexIsHidden) {
          $("#imageTitle").hide()
        } else {
          $("#imageTitle").show()
        }
      }

    }
  }

  def generateTcgaImage(logScale: String = "TRUE") = {
    getTcgaImage(logScale).map { rs =>
      val tcgaValid = rs("valid").toB
      if (tcgaValid) {
        val tcgaBase64 = rs("base64")
        val pdfBase64 = rs("pdfBase64")
        $("#tcgaCharts img").attr("src", s"data:image/png;base64,${tcgaBase64}")
        $("#tcgaCharts").findInputByName("pdfBase64").`val`(pdfBase64.toString)
        $("#tcgaResult").show()
      } else {
        Swal.swal(SwalOptions.title("Error").text(rs("message")).`type`("error"))
        $("#tcgaResult").hide()
      }
    }
  }

  def generateGtexImage(logScale: String = "TRUE") = {
    getGtexImage(logScale).map { rs =>
      val gtexValid = rs("valid").toB
      if (gtexValid) {
        val gtexBase64 = rs("base64")
        val pdfBase64 = rs("pdfBase64")
        $("#gtexCharts img").attr("src", s"data:image/png;base64,${gtexBase64}")
        $("#gtexCharts").findInputByName("pdfBase64").`val`(pdfBase64.toString)
        $("#gtexResult").show()
      } else {
        Swal.swal(SwalOptions.title("Error").text(rs("message")).`type`("error"))
        $("#gtexResult").hide()
      }
    }
  }

  @JSExport("boxplotRun")
  def boxplotRun = {
    val tabId = "boxplot"
    val bv = jQuery(s"#${tabId} #form").data("bootstrapValidator")
    bv.validate()
    val valid = bv.isValid().toB
    if (valid) {
      Tool.useLoadingF() { () =>
        val url = g.jsRoutes.controllers.SearchController.generateBoxplotImage().url.toString
        val formData = $(s"#${tabId} #form").serialize()
        Ajax.post(url = s"${url}", data = formData, headers = Map("Content-Type" -> "application/x-www-form-urlencoded"),
          responseType = "application/json").map { xhr =>
          val rs = xhr.responseText.toJDJAn
          val valid = rs("valid").toB
          if (valid) {
            val base64 = rs("base64")
            val pdfBase64 = rs("pdfBase64")
            $("#boxplotCharts img").attr("src", s"data:image/png;base64,${base64}")
            $("#boxplotCharts").findInputByName("pdfBase64").`val`(pdfBase64.toString)
            $(s"#${tabId} #result").show()
          } else {
            Swal.swal(SwalOptions.title("Error").text(rs("message")).`type`("error"))
            $("#result").hide()
          }
        }
      }
    }

  }

  @JSExport("survivalRun")
  def survivalRun = {
    val tabId = "survival"
    val bv = jQuery(s"#${tabId} #form").data("bootstrapValidator")
    bv.validate()
    val valid = bv.isValid().toB
    if (valid) {
      Tool.useLoadingF() { () =>
        val url = g.jsRoutes.controllers.SearchController.generateSurvivalImage().url.toString
        val formData = $(s"#${tabId} #form").serialize()
        Ajax.post(url = s"${url}", data = formData, headers = Map("Content-Type" -> "application/x-www-form-urlencoded"),
          responseType = "application/json").map { xhr =>
          val rs = xhr.responseText.toJDJAn
          val valid = rs("valid").toB
          if (valid) {
            val base64 = rs("base64")
            val pdfBase64 = rs("pdfBase64")
            $("#survivalCharts img").attr("src", s"data:image/png;base64,${base64}")
            $("#survivalCharts").findInputByName("pdfBase64").`val`(pdfBase64.toString)
            $(s"#${tabId} #result").show()
          } else {
            Swal.swal(SwalOptions.title("Error").text(rs("message")).`type`("error"))
            $(s"#${tabId} #result").hide()
          }
        }
      }
    }

  }

  def getJunctionId = {
    g.junctionId.toString
  }

  def getKind = {
    g.kind.toString
  }

  def isLeast(f: Int => Boolean): js.Function = { () => {
    val size = Tool.getInputByName("kinds[]").select2Val.size
    f(size)
  }
  }

  def bootStrapValidator = {
    val dict = js.Dictionary(
      "feedbackIcons" -> js.Dictionary(
        "valid" -> "glyphicon glyphicon-ok",
        "invalid" -> "glyphicon glyphicon-remove",
        "validating" -> "glyphicon glyphicon-refresh",
      ),
      "fields" -> js.Dictionary(
        "kinds[]" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "choice" -> js.Dictionary(
              "message" -> "Datasets Selection is required！",
              "min" -> 1
            ),
          )
        ),
      )
    )
    g.$("#boxplot #form").bootstrapValidator(dict)
    survivalBootStrapValidator
  }

  def survivalBootStrapValidator = {
    val dict = js.Dictionary(
      "feedbackIcons" -> js.Dictionary(
        "valid" -> "glyphicon glyphicon-ok",
        "invalid" -> "glyphicon glyphicon-remove",
        "validating" -> "glyphicon glyphicon-refresh",
      ),
      "fields" -> js.Dictionary(

      )
    )
    g.$("#survival #form").bootstrapValidator(dict)
  }


}
